# coding=utf-8
from __future__ import print_function, absolute_import

import os

import akshare as ak
import pandas as pd
from ewili.common import common as juejin_common
from ewili.common.code import code_to_shse_szse_symbol
from ewili.common.log import get_logger
from ewili.quant_api.juejin import order as juejin_order
from ewili.quant_api.juejin.juejin import *
from ewili.stock.amount import amount_in
from ewili.stock.extern_quant import dfcf_analysis
from ewili.stock.finance import finance_diag_newest_score_more_than
from ewili.stock.hot_event import ths_24_hot, eastmoney_recent_hot_theme, xue_qiu_point_found, \
    xue_qiu_hot_discuss, xue_qiu_hot_search_1h, xue_qiu_hot_search_24h, xue_qiu_up_rate, xue_qiu_cube_found, \
    todayopportunity
from ewili.stock.rise_properbliy import dfcf_next_day_rise_properbliy_more_than
from gm.api import *
from retry import retry

# from gmcache import *

log = get_logger(os.path.split(__file__)[-1].split(".")[0])


# 策略中必须有init方法
def init(context):
    log.info("测试")
    get_stocks_can_trade_today(context, False)
    context.stock_to_trade = list()
    select_stock(context)
    # 选股
    schedule(schedule_func=select_stock, date_rule='1d', time_rule='14:51:00')

    subscribe(symbols="SHSE.000300", frequency='tick', count=1, wait_group=True)


def on_tick(context, tick):
    # type: (Context, TickLikeDict2) -> NoReturn
    """
    tick数据推送事件
    参数 tick 为当前被推送的tick.
    tick包含的key值有下列值.
    symbol              str                   标的代码
    open                float                 日线开盘价
    high                float                 日线最高价
    low                 float                 日线最低价
    price               float	              最新价
    cum_volume          long                  成交总量/最新成交量,累计值
    cum_amount          float                 成交总金额/最新成交额,累计值
    trade_type          int                   交易类型 1: ‘双开’, 2: ‘双平’, 3: ‘多开’, 4: ‘空开’, 5: ‘空平’, 6: ‘多平’, 7: ‘多换’, 8: ‘空换’
    last_volume         int                   瞬时成交量
    cum_position        int                   合约持仓量(期),累计值（股票此值为0）
    last_amount         float                 瞬时成交额
    created_at          datetime.datetime     创建时间
    quotes              list[Dict]            股票提供买卖5档数据, list[0]~list[4]分别对应买卖一档到五档, 期货提供买卖1档数据, list[0]表示买卖一档. 目前期货的 list[1] ~ list[4] 值是没有意义的
        quotes 里每项包含的key值有:
          bid_p:  float   买价
          bid_v:  int     买量
          ask_p   float   卖价
          ask_v   int     卖量

    注: 可以使用属性访问的方式得到相应的key的值. 如要访问: symbol. 则可以使用 tick.symbol 或 tick['symbol']
    访问quote里的bid_p, 则可以使用 tick.quotes[0].bid_p  或 tick['quotes'][0]['bid_p']
    """
    if tick.symbol == 'SHSE.000300':
        juejin_order.auto_tp_sl_all_can_close_orders_market(context, 3, -3)


def on_bar(context, bars):
    for bar in bars:
        if bar.symbol in context.stock_list:
            account_positions = context.account().positions()
            if len(account_positions) < 10 and juejin_order.had_position(context, bar.symbol) is False:
                orders = juejin_order.do_order_at_market(bar.symbol, context.per_amount_to_trade)
                if len(orders) != 0:
                    print("完成下单", orders[0])


@retry(tries=-1, delay=3, backoff=2, max_delay=60)
def select_stock(context):
    """
    执行选股
    :param context:
    """
    # 题材
    today_hot_theme = todayopportunity()
    print('今日主题热点关联股\n' + str(today_hot_theme))

    recent_hot = eastmoney_recent_hot_theme()
    print('近期主题热点关联股\n' + str(recent_hot))

    theme = pd.merge(today_hot_theme, recent_hot, on=['代码'], how='outer').drop_duplicates('代码')

    # 人气
    stock_hot_rank_em_df = ak.stock_hot_rank_em()
    stock_hot_rank_em_df['代码'] = stock_hot_rank_em_df['代码'].str.replace('SZ', '').str.replace('SH', '')
    print('东方财富人气前100关联股\n' + str(stock_hot_rank_em_df))

    stock_hot_tgb_df = ak.stock_hot_tgb()
    stock_hot_tgb_df['个股代码'] = stock_hot_tgb_df['个股代码'].str.replace('sz', '').str.replace('sh', '')
    stock_hot_tgb_df.rename(columns={'个股代码': '代码'}, inplace=True)
    print('淘股吧人气前20关联股\n' + str(stock_hot_tgb_df))

    stock_hot_deal_xq_df = ak.stock_hot_deal_xq(symbol="最热门").head(100)
    stock_hot_deal_xq_df['股票代码'] = stock_hot_deal_xq_df['股票代码'].str.replace('SZ', '').str.replace('SH', '')
    stock_hot_deal_xq_df.rename(columns={'股票代码': '代码'}, inplace=True)
    print('雪球关注排行榜最热门\n' + str(stock_hot_deal_xq_df))

    stock_hot_follow_xq_new_df = ak.stock_hot_follow_xq(symbol="本周新增").head(100)
    stock_hot_follow_xq_new_df['股票代码'] = stock_hot_follow_xq_new_df['股票代码'].str.replace('SZ',
                                                                                                '').str.replace(
        'SH', '')
    stock_hot_follow_xq_new_df.rename(columns={'股票代码': '代码'}, inplace=True)
    print('雪球关注排行榜本周新增\n' + str(stock_hot_follow_xq_new_df))

    stock_hot_follow_xq_df = ak.stock_hot_follow_xq(symbol="最热门").head(100)
    stock_hot_follow_xq_df['股票代码'] = stock_hot_follow_xq_df['股票代码'].str.replace('SZ', '').str.replace('SH',
                                                                                                              '')
    stock_hot_follow_xq_df.rename(columns={'股票代码': '代码'}, inplace=True)
    print('雪球关注排行榜最热门\n' + str(stock_hot_follow_xq_df))

    xue_qiu_point_found_df = xue_qiu_point_found()
    print('雪球关注榜\n' + str(stock_hot_follow_xq_df))

    xue_qiu_hot_discuss_df = xue_qiu_hot_discuss()
    print('雪球热议榜单\n' + str(xue_qiu_hot_discuss_df))

    xue_qiu_hot_search_1h_df = xue_qiu_hot_search_1h()
    print('雪球一小时热搜榜单\n' + str(xue_qiu_hot_search_1h_df))

    xue_qiu_hot_search_24h_df = xue_qiu_hot_search_24h()
    print('雪球24小时热搜榜单\n' + str(xue_qiu_hot_search_24h_df))

    xue_qiu_up_rate_df = xue_qiu_up_rate()
    print('雪球飙升榜\n' + str(xue_qiu_up_rate_df))

    xue_qiu_cube_found_df = xue_qiu_cube_found()
    print('雪球组合榜\n' + str(xue_qiu_cube_found_df))

    ths_24_hot_df = ths_24_hot()
    print('同花顺24小时热门\n' + str(ths_24_hot_df))

    hot_rank = pd.merge(stock_hot_tgb_df, stock_hot_rank_em_df, on=['代码'], how='outer').drop_duplicates('代码')
    hot_rank = pd.merge(stock_hot_deal_xq_df, hot_rank, on=['代码'], how='outer').drop_duplicates('代码')
    hot_rank = pd.merge(stock_hot_follow_xq_new_df, hot_rank, on=['代码'], how='outer').drop_duplicates('代码')
    hot_rank = pd.merge(stock_hot_follow_xq_df, hot_rank, on=['代码'], how='outer').drop_duplicates('代码')
    hot_rank = pd.merge(ths_24_hot_df, hot_rank, on=['代码'], how='outer').drop_duplicates('代码')
    hot_rank = pd.merge(xue_qiu_point_found_df, hot_rank, on=['代码'], how='outer').drop_duplicates('代码')
    hot_rank = pd.merge(xue_qiu_cube_found_df, hot_rank, on=['代码'], how='outer').drop_duplicates('代码')
    hot_rank = pd.merge(xue_qiu_hot_discuss_df, hot_rank, on=['代码'], how='outer').drop_duplicates('代码')
    hot_rank = pd.merge(xue_qiu_hot_search_1h_df, hot_rank, on=['代码'], how='outer').drop_duplicates('代码')
    hot_rank = pd.merge(xue_qiu_hot_search_24h_df, hot_rank, on=['代码'], how='outer').drop_duplicates('代码')
    hot_rank = pd.merge(xue_qiu_up_rate_df, hot_rank, on=['代码'], how='outer').drop_duplicates('代码')

    # 技术
    # ths_tech_trade_df = ths_tech_trade()
    # print('同花顺技术信号前100\n' + str(ths_tech_trade_df))
    # ths_trend_invest_df = ths_trend_invest()
    # print('同花顺趋势前100\n' + str(ths_trend_invest_df))
    # tech = pd.merge(ths_tech_trade_df, ths_trend_invest_df, on=['代码'], how='outer').drop_duplicates('代码')

    # 资金
    # amount5 = amount5_in(10)
    # print('5日资金增仓占比大于10%\n' + str(amount5))
    # amount10 = amount10_in(0)
    # print('10日资金增仓占比大于10%\n' + str(amount10))
    # amount = pd.merge(amount5, amount10, on=['代码'], how='outer').drop_duplicates('代码')
    amount = amount_in(0)
    # amount = amount5
    print('今日资金增仓占比大于10%\n' + str(amount))

    is_ok = pd.merge(amount, theme, on=['代码'], how='inner').drop_duplicates('代码')
    is_ok = pd.merge(is_ok, hot_rank, on=['代码'], how='inner').drop_duplicates('代码')
    # is_ok = pd.merge(is_ok, tech, on=['代码'], how='inner').drop_duplicates('代码')
    print('条件取交集\n' + str(is_ok))

    # 财务面
    finance_filter_codes = list()
    for code in is_ok['代码']:
        # 财务面
        is_true = finance_diag_newest_score_more_than(code, 60)
        if is_true:
            finance_filter_codes.append(code)
    print("财务面", finance_filter_codes)

    # 统计概率面
    stat_filter_codes = list()
    for code in finance_filter_codes:
        is_true = dfcf_next_day_rise_properbliy_more_than(code, 50)
        if is_true:
            stat_filter_codes.append(code)
    print('统计概率', stat_filter_codes)

    # 价格是否在成交秘籍区域上方是否为非小单成交多
    level2_filter_codes = list()
    for code in stat_filter_codes:
        analysis_result = dfcf_analysis(code)
        level2 = analysis_result['zjdx']['level2'][0][0]
        dianping = analysis_result['qsyp']['dianping'][0]
        if level2['HandDesc'] != "小单" and "短期处于上升" in dianping['Comment']:
            jue_jin_code = code_to_shse_szse_symbol(code)
            level2_filter_codes.append(jue_jin_code)
    print("level2", level2_filter_codes)

    context.stock_to_trade = level2_filter_codes
    subscribe(symbols=level2_filter_codes, frequency='60s', count=1, unsubscribe_previous=True, wait_group=False)

    '''
    # 技术面
    tech_filter_codes = list()
    for code in stat_filter_codes:
        # 最新价大于x天内的最低价，同时小于x天内的最高价，并且股价低于x天的均线价
        new_code = rebuild_code(code)
        last_close, max_high, low_min, last_ma = ma_high_low_with_newest_close(context, new_code, 10, 100)
        if max_high > last_close > low_min and last_close < last_ma and (last_close - low_min) / low_min * 100 <= 5:
            loss_rate = (last_close - low_min) / low_min * 100
            earn_rate = (last_ma - last_close) / last_close * 100
            print(code, '止损', low_min, '止损空间', loss_rate, '止盈', last_ma, '止盈空间',
                  earn_rate, '预期盈亏比', earn_rate / loss_rate)
            tech_filter_codes.append(code)
    print("技术面", tech_filter_codes)
    '''

    '''
    context.stock_trades.insert(loc=0, column='代码', value=stock_to_trade)
    fund_amount_hot_max_price = pd.DataFrame()
    for code in fund_amount_hot['代码']:
        max_price = get_five_days_real_price(code)
        fund_amount_hot_max_price.append(code, max_price)
    
    '''


def on_order_status(context, order):
    # type: (Context, DictLikeOrder) -> NoReturn
    """
    委托状态更新事件. 参数order为委托信息
    响应委托状态更新事情，下单后及委托状态更新时被触发
    """


'''
    send_mail(['378981649@qq.com', '15225163568@163.com', '8171973@qq.com', '453030700@qq.com'],
              '资金流策略，订单状态发生变化',
              str(order))'''


def on_execution_report(context, execrpt):
    # type: (Context, DictLikeExecRpt) -> NoReturn
    """
    委托执行回报事件. 参数 execrpt 为执行回报信息
    响应委托被执行事件，委托成交后被触发
    """
    '''
    send_mail(['378981649@qq.com', '15225163568@163.com', '8171973@qq.com', '453030700@qq.com'],
              '资金流策略，委托单被执行',
              str(execrpt))'''


def on_account_status(context, account_status):
    # type: (Context, DictLikeAccountStatus) -> NoReturn
    """
    交易账户状态变更事件. 仅响应 已连接，已登录，已断开 和 错误 事件
    account_status: 包含account_id(账户id), account_name(账户名),ConnectionStatus(账户状态)
    """
    '''
    send_mail(['378981649@qq.com'],
              '资金流策略，帐户链接状态发生变化',
              str(account_status))'''


def on_parameter(context, parameter):
    # type: (Context, DictLikeParameter) -> NoReturn
    """
    动态参数修改事件推送. 参数 parameter 为动态参数的信息
    """
    pass


def on_backtest_finished(context, indicator):
    # type: (Context, DictLikeIndicator) -> NoReturn
    """
    回测结束事件. 参数 indicator 为此次回测的绩效指标参数信息

    """
    pass


def on_error(context, code, info):
    # type: (Context, int, Text) -> NoReturn
    """
    底层sdk出错时的回调函数
    :param context:
    :param code: 错误码.  参考: https://www.myquant.cn/docs/python/python_err_code
    :param info: 错误信息描述
    """
    juejin_common.send_mail(['378981649@qq.com'],
                            '资金流策略，运行错误警告',
                            'code:{}, info:{}'.format(code, info))


def on_trade_data_connected(context):
    # type: (Context) -> NoReturn
    """
    交易通道网络连接成功事件

    send_mail(['378981649@qq.com'],
              '资金流策略，交易通道网络连接成功通知',
              '交易通道网络连接成功')
    """
    pass


def on_market_data_connected(context):
    # type: (Context) -> NoReturn
    """
    实时行情网络连接成功事件

    send_mail(['378981649@qq.com'],
              '资金流策略，实时行情网络连接成功通知',
              '实时行情网络连接成功')
    """
    pass


def on_market_data_disconnected(context):
    # type: (Context) -> NoReturn
    """
    实时行情网络连接断开事件

    send_mail(['378981649@qq.com'],
              '资金流策略，实时行情网络连接断开通知',
              '实时行情网络连接断开')
    """
    pass


def on_trade_data_disconnected(context):
    # type: (Context) -> NoReturn
    """
    交易通道网络连接断开事件

    send_mail(['378981649@qq.com'],
              '资金流策略，交易通道网络连接失败通知',
              '交易通道网络连接失败')
    """
    pass


def on_shutdown(context):
    # type: (Context) -> NoReturn
    """
    策略退出前回调

    send_mail(['378981649@qq.com'],
              '资金流策略，交易策略退出通知',
              '交易策略已退出')
    """
    pass
